package opc.read.utils;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description: 读写分离的Map;参考       CopyOnWriteArraySet   CopyOnWriteArrayList;
 * @author: liyuan
 * @data 2021-01-07 08:57
 * https://zhuanlan.zhihu.com/p/340721685
 */
public class MyCopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
    //    ConashMap //线程安全的
//    CopyOnWriteMap //kafka的，线程安全，put方法加锁了
    public volatile Map<K, V> map;
    //不可以序列化关键字transient； 重入锁
    private ReentrantLock lock = new ReentrantLock();

    public MyCopyOnWriteMap(Map<K, V> paraMap) {
        map = paraMap;
    }

    public MyCopyOnWriteMap(int i) {
        map = new HashMap<K, V>(i);
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return map.containsValue(value);
    }

    //读取不需要加锁
    @Override
    public V get(Object key) {
        return map.get(key);
    }

    @Override
    public V put(K key, V value) {
        try {
            lock.lock();
            Map<K, V> newMap = new HashMap<K, V>(map);
            V v = newMap.put(key, value);
            map = newMap;
            return v;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }

    @Override
    public V remove(Object key) {
        try {
            lock.lock();
            V v = map.remove(key);
            return v;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        try {
            lock.lock();
            Map<K, V> newMap = new HashMap<K, V>(map);
            newMap.putAll(m);
            map = newMap;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void clear() {
        try {
            lock.lock();
            map.clear();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Set<K> keySet() {
        return map.keySet();
    }

    @Override
    public Collection<V> values() {
        return map.values();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        return map.entrySet();
    }
}
